package model.simulationmodel;

import java.util.ArrayList;
import java.util.Map;

import model.simulationmodel.logicelements.LogicSimulationElement;

/**
 * <b>In Verbindung stehende Klassen:</b> <code>LogicSimulationElement</code><br>
 * <b>Funktion:</b> Dient zur Kommunikation zwischen
 * <code>SimulationModel</code> und <code>SimulationArea</code>. Beinhaltet
 * einen Nachrichtentyp und die fuer die View benoetigten Objekte.<br>
 * <br>
 * 
 * Wird beim Aufruf von <code>notifyObservers</code> als Objekt mitgegeben.
 * 
 * @author Team Locsi
 * 
 */
public class SimulationMessage {

	/**
	 * Dieses Enum stellt den Nachrichtentyp, der angibt welche Operation im
	 * Simulationsmodus angewandt wurde, zur Verfuegung.
	 * 
	 * @author Team Locsi
	 * 
	 */
	public static enum SimulationMessageType {
		SET_SWITCH, SET_CLOCK, START_SIMULATION, PAUSE_SIMULATION, STOP_SIMULATION, RESUME_SIMULATION, UPDATED_ELEMENTS, UPDATE_AFTER_CALC, CLOCK_FREQUENCY, TOO_MUCH_SETTERS, START_TRUTH_TABLE, STATUS_TRUTH_TABLE, END_TRUTH_TABLE, OSZILLATION_FOUND, FIRST_CALC_COMPLETE
	}

	private SimulationMessageType msgType;
	private Map<String, LogicSimulationElement> objectMap;
	private LogicSimulationElement sEl;
	private LogicValue[][] truthTable;
	private ArrayList<LogicSimulationElement> setter;
	private ArrayList<LogicSimulationElement> getter;
	private Thread[] threadsForTruthTable;

	/**
	 * Dieser Konstruktor erzeugt ein neues <code>SimulationMessage</code>
	 * -Objekt.
	 * 
	 * @param msgType
	 *            <code>SimulationMessageType</code> - Art der Nachricht
	 * @param objects
	 *            <code>Map</code> <<code>String, LogicSimulationElement></code>
	 *            - Objekte, die fuer die jeweilige Operation benoetigt werden
	 *            (der Nachrichtentyp gibt die Operation an)
	 */
	public SimulationMessage(SimulationMessageType msgType,
			Map<String, LogicSimulationElement> objects) {
		this.objectMap = objects;
		this.msgType = msgType;
	}

	/**
	 * Dieser Konstruktor erzeugt ein neues <code>SimulationMessage</code>
	 * -Objekt
	 * 
	 * @param msgType
	 *            <code>SimulationMessageType</code> - Art der Nachricht
	 * @param sEl
	 *            <code>LogicSimulationElement</code> - Objekt, das fuer die
	 *            jeweilige Operation benoetigt wird
	 */
	public SimulationMessage(SimulationMessageType msgType,
			LogicSimulationElement sEl) {
		this.msgType = msgType;
		this.sEl = sEl;
	}

	/**
	 * Dieser Konstruktor erzeugt ein neues <code>SimulationMessage</code>
	 * -Objekt
	 * 
	 * @param msgType
	 *            <code>SimulationMessageType</code> - Art der Nachricht
	 * @param tTable
	 *            <code>LogicValue[][]</code> - Wahrheitstabelle
	 * @param setter
	 *            <code>ArrayList</code><<code>LogicSimulationElement></code> -
	 *            ArrayListe der Setter Elemente
	 * @param getter
	 *            <code>ArrayList</code><<code>LogicSimulationElement></code> -
	 *            ArrayListe der Getter Elemente
	 */
	public SimulationMessage(SimulationMessageType msgType,
			LogicValue[][] tTable, ArrayList<LogicSimulationElement> setter,
			ArrayList<LogicSimulationElement> getter) {
		this.msgType = msgType;
		this.truthTable = tTable;
		this.setter = setter;
		this.getter = getter;
	}

	/**
	 * Konstruktor der verwendet wird, wenn das erzeugen der Wahrheitstabelle
	 * gestartet wird. Hat als Argument ein Array der an der Berechnung
	 * beteiligten Threads.
	 * 
	 * @param msgType
	 *            Typ der Nachricht (solltein dem Fall START_TRUTH_TABLE sein)
	 * @param threads
	 *            Array der beteiligten Threads
	 */
	public SimulationMessage(SimulationMessageType msgType,
			LogicValue[][] truthTable, Thread[] threads) {
		this.threadsForTruthTable = threads;
		this.truthTable = truthTable;
		this.msgType = msgType;
	}

	/**
	 * Dieser Konstruktor erzeugt ein neues <code>SimulationMessage</code>
	 * -Objekt
	 * 
	 * @param msgType
	 *            <code>SimulationMessageType</code> - Art der Nachricht
	 */
	public SimulationMessage(SimulationMessageType msgType) {
		this.msgType = msgType;
	}

	/**
	 * Gibt die Art der Nachricht zurueck.
	 * 
	 * @return <code>SimulationMessageType</code> - die Art der Nachricht
	 */
	public SimulationMessageType getMsgType() {
		return msgType;
	}

	/**
	 * Gibt eine Wahrheitstabelle zurueck
	 * 
	 * @return <code>LogicValue[][]</code> - eine Wahrheitstabelle
	 */
	public LogicValue[][] getTruthTable() {
		return this.truthTable;
	}

	/**
	 * Gibt das Array der Threads zurueck die an der Berechnung der
	 * Wahrheitstabelle beteiligt sind.
	 * 
	 * @return Thread[] beteiligte Threads
	 */
	public Thread[] getThreadsAtTruthTableCalc() {
		return this.threadsForTruthTable;
	}

	/**
	 * Gibt eine ArrayListe von Setter zurueck
	 * 
	 * @return <code>ArrayList</code><<code>LogicSimulationElement></code> -
	 *         Setter des LogicSimulationElements
	 */
	public ArrayList<LogicSimulationElement> getSetter() {
		return this.setter;
	}

	/**
	 * Gibt eine ArrayListe von Getter zurueck
	 * 
	 * @return <code>ArrayList</code><<code>LogicSimulationElement></code> -
	 *         Getter des LogicSimulationElements
	 */
	public ArrayList<LogicSimulationElement> getGetter() {
		return this.getter;
	}

	/**
	 * Gibt die Objekte zurueck, die fuer die jeweilige Operation benoetigt
	 * werden.
	 * 
	 * @return <code>Map</code><<code>String, LogicSimulationElement></code> -
	 *         die fuer die jeweilige Operation benoetigten Objekte
	 */
	public Map<String, LogicSimulationElement> getObjectMap() {
		return this.objectMap;
	}

	/**
	 * Gibt das Objekt zurueck, die fuer die jeweiligen Operation benoetigt
	 * wird.
	 * 
	 * @return <code>LogicSimulationElement</code> - das fuer die jeweilige
	 *         Operation benoetigte Objekt
	 */
	public LogicSimulationElement getSimElement() {
		return this.sEl;
	}
}